package com.naiterui.ehp.bs.esign.service.impl;

import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import com.google.common.collect.Lists;
import com.itextpdf.text.DocumentException;
import com.naiterui.ehp.bp.bo.ca.EmrSignBO;
import com.naiterui.ehp.bp.bo.patient.PatientInquirerBO;
import com.naiterui.ehp.bp.support.exception.BusinessException;
import com.naiterui.ehp.bp.utils.date.DateUtil;
import com.naiterui.ehp.bp.utils.lang.ConfigUtil;
import com.naiterui.ehp.bs.esign.api.ISignService;
import com.naiterui.ehp.bs.esign.api.ISignService.SealPosVO;
import com.naiterui.ehp.bs.esign.api.bjca.vo.SignFileUploadVO;
import com.naiterui.ehp.bs.esign.api.vo.SignAccountVO;
import com.naiterui.ehp.bs.esign.api.vo.SignFileSnVO;
import com.naiterui.ehp.bs.esign.entity.mongo.MedicalRecord;
import com.naiterui.ehp.bs.esign.entity.mongo.MedicalRecordDoctor;
import com.naiterui.ehp.bs.esign.entity.mongo.SignInfo;
import com.naiterui.ehp.bs.esign.exception.ExceptionCodes;
import com.naiterui.ehp.bs.esign.feign.IPatientFeignClient;
import com.naiterui.ehp.bs.esign.repository.mongo.EsignMedicalRecordRepository;
import com.naiterui.ehp.bs.esign.service.IDoctorService;
import com.naiterui.ehp.bs.esign.service.IEmrService;
import com.naiterui.ehp.bs.esign.service.IEsignService;
import com.naiterui.ehp.bs.esign.utils.EsignEmrPdfUtil;
import com.naiterui.ehp.bs.esign.vo.esign.PreSignResultVO;

import cn.hutool.core.collection.CollUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * @author guoyongxiang
 * @date 2019/9/10 20:04
 * @since 1.0.0
 */
@Slf4j
@Service
public class EsignEmrServiceImpl implements IEmrService {

    private static final String HOSPITAL_NAME = ConfigUtil.getString("ehp.hospital.name");

    @Autowired
    private EsignMedicalRecordRepository esignMedicalRecordRepository;
    @Autowired
    private EsignEmrPdfUtil esignEmrPdfUtil;
    @Value("${file.base.prefix}")
    private String basePath;

    @Autowired
    private IEsignService esignService;
    @Autowired
    private IPatientFeignClient patientFeignClient;

    @Autowired
    private IDoctorService doctorService;

    @Autowired
    private ISignService signService;

    @Override
    public EmrSignBO getUnionId(String emrId, Long inquirerId, Integer requestFrom) throws BusinessException {
        MedicalRecord medicalRecord = esignMedicalRecordRepository.findByIdAndCaseTypeAndAvailableNot(
            emrId, MedicalRecord.CASETYPE_DOCTORRECORD, MedicalRecord.AVAILABLE_YES);
        if (medicalRecord == null) {
            throw new BusinessException(ExceptionCodes.RECORD_NOT_EXIST);
        }
        //生成pdf
        String filePath = "";
        try {
            log.info("生成pdf文件开始, emr={}", emrId);
            filePath = this.generatePdf(medicalRecord, inquirerId);
            log.info("生成pdf文件成功：filepath={}", filePath);
        } catch (IOException e) {
            throw new BusinessException(ExceptionCodes.EMR_PDF_CREATE_FAIL);
        } catch (DocumentException d) {
            throw new BusinessException(ExceptionCodes.EMR_PDF_CREATE_FAIL);
        } catch (ReflectiveOperationException e) {
            throw new BusinessException(ExceptionCodes.EMR_PDF_CREATE_FAIL);
        }

        SignFileUploadVO vo = this.getFileUploadVO(medicalRecord);
        vo.setPdfPath(basePath + filePath);

        SignAccountVO signAccountVO = doctorService.getSignAccount(medicalRecord.getDoctorId(), vo.getUnionId());
        // 医生系统自动签名时，入口指定请求来源，未指定表示默认来源app
        if (requestFrom != null) {
            signAccountVO.setRequestFrom(requestFrom);
        }
        //获取预签署id
        PreSignResultVO resultVO = esignService.preSignPdf(vo, signAccountVO);
        log.info("病例预签名成功：unionId={}", resultVO.getUniqueId());

        return EmrSignBO.builder()
            .filePath(filePath).uniqueId(resultVO.getUniqueId()).faceUrl(resultVO.getUrl()).createdAt(new Date())
            .build();
    }

    @Override
    public void sign(String emrId, String pin, Integer requestFrom) throws BusinessException {
        log.info("签名开始,bo={}", emrId);
        MedicalRecord medicalRecord = esignMedicalRecordRepository.findByIdAndCaseTypeAndAvailableNot(
            emrId, MedicalRecord.CASETYPE_DOCTORRECORD, MedicalRecord.AVAILABLE_YES);
        if (medicalRecord == null) {
            throw new BusinessException(ExceptionCodes.RECORD_NOT_EXIST);
        }

        if (medicalRecord.getSignInfo() == null) {
            throw new BusinessException(ExceptionCodes.ESIGN_PRE_SIGN_FAILED);
        }

        //签名信息
        SignInfo signInfo = medicalRecord.getSignInfo();

        SignFileUploadVO vo = this.getFileUploadVO(medicalRecord);
        vo.setPdfPath(basePath + signInfo.getFiles().get(0).getPath());
        vo.setUnionId(signInfo.getUnionId());

        SignAccountVO signAccountVO = doctorService.getSignAccount(medicalRecord.getDoctorId(), signInfo.getUnionId());
        signAccountVO.setPin(pin);
        // 医生系统自动签名时，入口指定请求来源，未指定表示默认来源app
        if (requestFrom != null) {
            signAccountVO.setRequestFrom(requestFrom);
        }
        esignService.sign(vo, signAccountVO);
    }

    private String generatePdf(MedicalRecord medicalRecord, Long inquirerId)
        throws IOException, DocumentException, BusinessException, ReflectiveOperationException {
        List<String> imgFiles =
                Optional.ofNullable(medicalRecord)
                        .map(MedicalRecord::getRecordDoctor)
                        .map(MedicalRecordDoctor::getImgList)
                        .map(l -> l.stream().map(img -> basePath + img.getUrl()).collect(Collectors.toList()))
                        .orElse(null);

        //获取就诊人信息
        List<PatientInquirerBO> inquirerBOS = patientFeignClient.getPatientInquirer(Lists.newArrayList(inquirerId));
        if(CollectionUtils.isEmpty(inquirerBOS)){
            log.error("就诊人信息不存在：inquirerId={}", inquirerId);
            throw new BusinessException(ExceptionCodes.USER_NOT_EXIST);
        }
        PatientInquirerBO inquirer = inquirerBOS.get(0);

        EsignEmrPdfUtil.EmrBO emrBO = EsignEmrPdfUtil.EmrBO.builder()
            .emrId(medicalRecord.getId())
            .patientId(medicalRecord.getPatientId())
            .name(medicalRecord.getName())
            .age(medicalRecord.getAgeStr())
            .ageUnit(medicalRecord.getAgeUnit())
            .birthday(DateUtil.formatDate(inquirer.getBirthday(), DateUtil.DATE_FORMAT))
            .address(inquirer.getAddress())
            .idcard(inquirer.getIdCard())
            .maritalStatus(inquirer.getMaritalStatus())
            .phone(inquirer.getPhone())
            .departmentName(medicalRecord.getDepartment())
            .createdAt(medicalRecord.getCreateAt())
            .gender(medicalRecord.getGender())
            .chiefComplaint(medicalRecord.getRecordDoctor().getMainComplaint())
            .presentDisease(medicalRecord.getRecordDoctor().getPresentDisease())
            .pastMedicalHistory(medicalRecord.getRecordDoctor().getPastHistory())
            .temperature(medicalRecord.getRecordDoctor().getTemperature())
            .weight(medicalRecord.getRecordDoctor().getWeight())
            .heartRate(medicalRecord.getRecordDoctor().getHeartRete())
            .systolicPressure(medicalRecord.getRecordDoctor().getSystolic())
            .diastolicPressure(medicalRecord.getRecordDoctor().getDiastole())
            .diagnosis(medicalRecord.getRecordDoctor().getDiagnosisList())
            .doctorName(medicalRecord.getDoctorName())
            .hospitalName(HOSPITAL_NAME)
            .reportImgUrls(imgFiles)
            .allergy(medicalRecord.getRecordDoctor().getAllergy())
            .contact(medicalRecord.getRecordDoctor().getContactName())
            .contactPhone(medicalRecord.getRecordDoctor().getContactPhone())
            .menstrual(Optional.ofNullable(medicalRecord.getRecordDoctor().getMenstrual()).map(menstrual ->
                (menstrual.getStatus() != null && menstrual.getStatus() == 1) ?
                    String.join("；  ", "月经情况:已初潮",
                    "初潮年龄:" + (menstrual.getFirstAge() == null? "" : menstrual.getFirstAge() + "岁"),
                    "是否痛经:" + (menstrual.getDysmenorrhea() == null? "" : menstrual.getDysmenorrhea() == 1 ? "是" : "否"),
                    "痛经部位:" + (menstrual.getPart() == null? "" : menstrual.getPart()),
                    "行经周期:" + (menstrual.getCycle() == null? "" : menstrual.getCycle() + "天"),
                    "行经天数:" + (menstrual.getProcessDays() == null? "" : menstrual.getFirstAge() + "天")):
                "月经情况:" + (menstrual.getStatus() == null ? "未填写" : menstrual.getStatus() == 0 ? "未初潮"
                    : "已绝经")
            ).orElse(
                "未填写")
            )
            .moreExamine(medicalRecord.getRecordDoctor().getMoreExamin())
            .negativeSigns(medicalRecord.getRecordDoctor().getNegativeSigns())
            .pastFamily(medicalRecord.getRecordDoctor().getPastFamily())
            .positiveSigns(medicalRecord.getRecordDoctor().getPositiveSigns())
            .treatmentOptions(medicalRecord.getRecordDoctor().getTreatmentOptions())
            .medicalRecordSettingList(CollUtil.isNotEmpty(medicalRecord.getMedicalRecordSettingList())
                ? medicalRecord.getMedicalRecordSettingList() : null)
            .build();

        log.info("病例：{}", medicalRecord);
        return esignEmrPdfUtil.generatePDF(emrBO);
    }


    private SignFileUploadVO getFileUploadVO(MedicalRecord record) {

        SealPosVO sealPosVO = this.signService.getSealPosConfig().getEmrPos();
        //拼装vo,文件路径各自配置
        return SignFileUploadVO.builder()
            .bizSn(record.getId())
            .createdAt(record.getCreateAt())
            .patientAge(record.getAge() + "")
            .patientGender(record.getGender())
            .patientName(record.getName())
            .signFileType(SignFileSnVO.FILE_TYPE_EMR)
            .signUserId(record.getDoctorId())
            .signUserType(SignFileUploadVO.USER_TYPE_DR)
            .stampX(sealPosVO.getX())
            .stampY(sealPosVO.getY())
            .keyword(sealPosVO.getKeyword())
                               .build();
    }

}
